package io.kwdb.examples;

import io.kwdb.sdk.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Quick start example for KWDB Java SDK using gRPC. Demonstrates basic operations: single write,
 * batch write, and query.
 */
public class Example01_GrpcQuickStart {

  public static void main(String[] args) {
    System.out.println("=== KWDB Java SDK M1 Example - gRPC Quick Start ===\n");

    // Configure the client
    Config config = Config.builder().host("127.0.0.1").port(9090).timeoutMillis(30000).build();

    System.out.println("Connecting to KWDB at " + config.getHost() + ":" + config.getPort());

    // Create the client using try-with-resources for automatic cleanup
    try (KwdbClient client = KwdbClient.create(config)) {

      // 1. Single point write (using measurement name sdk_bench)
      System.out.println("\n1. Writing single point...");
      Point singlePoint =
          Point.builder("sdk_bench")
              .tag("host", "java-test-01")
              .tag("region", "us-west")
              .field("usage", 0.75)
              .timestampNow()
              .build();

      Status writeStatus = client.write(singlePoint);
      if (writeStatus.isOk()) {
        System.out.println("    Single point write succeeded");
      } else {
        System.out.println("    Single point write failed: " + writeStatus.getMessage());
      }

      // 2. Batch write
      System.out.println("\n2. Writing batch of 5 points...");
      List<Point> batch = new ArrayList<>();
      long baseTime = System.currentTimeMillis() * 1_000_000; // Convert to nanos

      for (int i = 0; i < 5; i++) {
        Point p =
            Point.builder("sdk_bench")
                .tag("host", "java-batch-" + (i + 1))
                .tag("region", (i % 2 == 0) ? "us-west" : "us-east")
                .field("usage", 0.5 + i * 0.1)
                .timestamp(baseTime + i * 1_000_000_000L) // 1 second apart
                .build();
        batch.add(p);
      }

      Status batchStatus = client.batchWrite(batch);
      if (batchStatus.isOk()) {
        System.out.println("    Batch write of " + batch.size() + " points succeeded");
      } else {
        System.out.println("    Batch write failed: " + batchStatus.getMessage());
      }

      // 3. Query - COUNT
      System.out.println("\n3. Executing COUNT query...");
      String countSql = "SELECT COUNT(*) FROM sdk_bench";
      QueryResult countResult = client.query(countSql);

      if (countResult.isSuccess()) {
        System.out.println("    Query succeeded");
        if (countResult.hasRows()) {
          QueryResult.Row row = countResult.getRows().get(0);
          Object count = row.getValue("count");
          System.out.println("   Total rows in temperature table: " + count);
        } else {
          System.out.println("   No rows returned");
        }
      } else {
        System.out.println("    Query failed: " + countResult.getStatus().getMessage());
      }

      // 4. Query - SELECT with conditions
      System.out.println("\n4. Executing SELECT query...");
      String selectSql = "SELECT host, region, usage FROM sdk_bench LIMIT 5";
      QueryResult selectResult = client.query(selectSql);

      if (selectResult.isSuccess()) {
        System.out.println("    Query succeeded");
        System.out.println("   Returned " + selectResult.getRowCount() + " rows");

        // Print column headers
        if (selectResult.getColumnCount() > 0) {
          System.out.print("   Columns: ");
          for (QueryResult.Column col : selectResult.getColumns()) {
            System.out.print(col.getName() + " ");
          }
          System.out.println();
        }

        // Print first few rows
        int rowsToPrint = Math.min(3, selectResult.getRowCount());
        for (int i = 0; i < rowsToPrint; i++) {
          QueryResult.Row row = selectResult.getRows().get(i);
          System.out.println("   Row " + (i + 1) + ": " + row.getValues());
        }

        if (selectResult.getRowCount() > rowsToPrint) {
          System.out.println(
              "   ... (" + (selectResult.getRowCount() - rowsToPrint) + " more rows)");
        }
      } else {
        System.out.println("    Query failed: " + selectResult.getStatus().getMessage());
      }

      // 5. Error handling demonstration
      System.out.println("\n5. Testing error handling...");

      // Test invalid point (empty measurement)
      try {
        Point invalidPoint = Point.builder("").field("value", 1.0).build();
        Status status = client.write(invalidPoint);
        System.out.println(
            "   Invalid point handling: "
                + (status.isError() ? " Correctly rejected" : " Should have failed"));
      } catch (IllegalArgumentException e) {
        System.out.println(
            "    Invalid point correctly rejected at build time: " + e.getMessage());
      }

      // Test invalid SQL
      QueryResult invalidResult = client.query("INVALID SQL SYNTAX");
      System.out.println(
          "   Invalid SQL handling: "
              + (invalidResult.isSuccess() ? " Should have failed" : " Correctly rejected"));

      // Test connection failure (assuming service might not be running)
      System.out.println("\n6. Testing connection resilience...");
      Config badConfig =
          Config.builder()
              .host("127.0.0.1")
              .port(19999) // Wrong port
              .timeoutMillis(3000) // Short timeout
              .build();

      try (KwdbClient badClient = KwdbClient.create(badConfig)) {
        Status status = badClient.write(singlePoint);
        if (status.isError()) {
          System.out.println("    Connection failure handled gracefully: " + status.getMessage());
        } else {
          System.out.println("    Unexpected success on bad connection");
        }
      } catch (Exception e) {
        System.out.println("   Client close error (expected): " + e.getMessage());
      }

      System.out.println("\n=== Example completed successfully ===");

    } catch (Exception e) {
      System.err.println("Fatal error: " + e.getMessage());
      e.printStackTrace();
      System.exit(1);
    }
  }
}
